package com.lmaos.basetools.files;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;

import com.lmaos.basetools.base.SNumberUtils;
import com.lmaos.basetools.sText.FileUtils;
import com.lmaos.basetools.sText.TextUtils;

public class FileListenerThread implements Runnable{
	FileListener fileListener;
	List<File> paths = null;
	Map<String, Long> upTimes = new HashMap<String, Long>();
	String suffixs[];
	volatile boolean start = true; 
	long sleep = 5000;
	Executor exec;
	public boolean end(String text){
		if(suffixs==null||suffixs.length==0){
			return true;
		}
		for (String suffix : suffixs) {
			if(!TextUtils.isBlank(suffix)&&text.endsWith(suffix)){
				return true;
			}
		}
		return false;
	}
	/**	文件监听线程
	 * 
	 * @param superPath		监听根目录
	 * @param fileListener	文件监听处理的对象
	 * @param sleep			观察者模式,扫描时间
	 * @param exec			线程池，如果为null 则不使用线程池处理监控
	 * @param suffixs		文件拦截,拦截后缀为这些的文件
	 */
	public FileListenerThread(File superPath,FileListener fileListener,long sleep,Executor exec,String...suffixs) {
		this.fileListener = fileListener;
		this.suffixs = suffixs;
		this.sleep = sleep;
		this.exec = exec;
		paths = FileUtils.getFileAll(superPath);
		Iterator<File> files_it = paths.iterator();
		while(files_it.hasNext()){
			File file = files_it.next();
			if(file.isFile()&&!end(file.getName())){
				files_it.remove();
			}else{
				upTimes.put(file.getAbsolutePath(), file.lastModified());
				execFileRUN(new FileRUN(fileListener, file).setIsdir(file.isDirectory()).setOnload());
			}
		}
	}

	@Override
	public void run() {
		
		while(start){
			try {
				exec();
				Thread.sleep(sleep);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	public void exec() throws Exception{
		List<File> newFiles = new ArrayList<File>();
		Iterator<File> files_it = paths.iterator();
		while(files_it.hasNext()){
			File file = files_it.next();
			String absolutePath = file.getAbsolutePath();
			long time = SNumberUtils.toLong(upTimes.get(absolutePath),0);
			boolean dir = file.isDirectory();
			boolean exist=file.exists();
			boolean timechg=file.lastModified()!=time; // 时间改变
			if(exist){
				// 如果被改变
				if(timechg){
					if(dir){
						
						List<File> cPaths = new ArrayList<File>();//FileUtils.getFileAll(file);
						cPaths.add(file);
						for (int ci=0;ci<cPaths.size();ci++) {
							File cfile = cPaths.get(ci);
							
							File[]ccfiles = cfile.listFiles(); 
							for (File ccfile : ccfiles) {
								
								String ccabsolutePath = ccfile.getAbsolutePath();
								
								if(!upTimes.containsKey(ccabsolutePath)){
									if(ccfile.isDirectory()){
										cPaths.add(ccfile); // 新创建的子目录 继续查询
									}else if(!end(ccfile.getName())){
										continue;
									}
									
									
									long upTime = ccfile.lastModified();
									newFiles.add(ccfile);
									upTimes.put(ccabsolutePath, upTime);
									execFileRUN(new FileRUN(fileListener, ccfile).setIsdir(ccfile.isDirectory()).setCreate());
								}
							}
						}
					}
					execFileRUN(new FileRUN(fileListener, file).setIsdir(dir).setChange());
					upTimes.put(absolutePath, file.lastModified());
				}
			}else{
				files_it.remove();
				upTimes.remove(absolutePath);
				execFileRUN(new FileRUN(fileListener, file).setIsdir(dir).setDelete());
			}
		}
		this.paths.addAll(newFiles);
	}

	
	public void execFileRUN(FileRUN fileRUN){
		if(exec == null){
			fileRUN.start();
		}else{
			exec.execute(fileRUN);
		}
	}
	public class FileRUN extends Thread implements Runnable{
		FileListener fileListener;
		File file;
		
		public FileRUN(FileListener fileListener, File file) {
			this.fileListener = fileListener;
			this.file = file;
		}

		boolean change;
		boolean create;
		boolean delete;
		boolean onload;
		boolean isdir;
		
		public FileRUN setIsdir(boolean isdir) {
			this.isdir = isdir;
			return this;
		}
		public FileRUN setOnload() {
			this.onload = true;
			return this;
		}
		public FileRUN setChange() {
			this.change = true;
			return this;
		}


		public FileRUN setCreate() {
			this.create = true;
			return this;
		}


		public FileRUN setDelete() {
			this.delete = true;
			return this;
		}




		@Override
		public void run() {
			
			if(!isdir&&change){
				fileListener.fileChange(file);
			}else if(!isdir&&create){
				fileListener.fileCreate(file);
			}else if(!isdir&&delete){
				fileListener.fileDelete(file);
			}else if(!isdir&&onload){
				fileListener.fileOnLoad(file);
			}else if(change){
				fileListener.directoryChange(file);
			}else if(create){
				fileListener.directoryCreate(file);
			}else if(delete){
				fileListener.directoryDelete(file);
			}else if(onload){
				fileListener.directoryOnLoad(file);
			}
		}
	}
	
}
